using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DunGenAlgo {
	
	
	// Code Based on BSP Dungeon Outline from http://roguebasin.roguelikedevelopment.org/index.php/Basic_BSP_Dungeon_generation
	
	public Node root;
	public Params paras;
	public List<Node> curListofChi = new List<Node>();
	public List<Line> listOfSplits = new List<Line>();
	public List<Rectangles> roomsforShow = new List<Rectangles>();
	public List<Node> leafs = new List<Node>();
	public List<Rectangles> hallways = new List<Rectangles>();
	public Node Aers = null;
	public Node Bers = null;
	public float aa,ab,ac,ad,ba,bb,bc,bd;
	
	public int howMany = 0;
	
	// Use this for initialization
	public void Start (Params pars) {
	root = new Node();
	paras = pars;
	root.AddRectangle(paras.dunSize);
	curListofChi.Add(root);
	}
	
	// Update is called once per frame
	void Update () {
	
	}
	
	public void Split(Node curNode)
	{
		bool breakout = false;
	if(curNode.didSplit)
		{
			Split(curNode.children[0]);
			Split(curNode.children[1]);
			breakout = true;
		}
			if(breakout) return;
			
		float sizeofWidth = curNode.myRectangle.width;
		float sizeofHeight = curNode.myRectangle.height;
		
		
		if(sizeofWidth/paras.ratio>sizeofHeight)
		{
				splitVert(curNode);	
				breakout = true;
		}
		
		if(sizeofWidth<sizeofHeight/paras.ratio)
		{
			splitHorz(curNode);
			breakout = true;
		}
		
		if(breakout) return;	
		
		float whichSplit = Random.Range(0,3);
			if (whichSplit <= 1.5)//horizontal
			{
			  splitHorz(curNode);
			}
		else
			{
			splitVert(curNode);	
			}
		
		
			return;
		
	}
	
	public void generateRoom(Node curNode)
	{
		float sizeofWidth = curNode.myRectangle.width;
		float sizeofHeight = curNode.myRectangle.height;
		bool breakout = false;
	if(curNode.didSplit)
		{
			generateRoom(curNode.children[0]);
			generateRoom(curNode.children[1]);
			breakout = true;
		}
			if(breakout) return;
		Rectangles here = new Rectangles();
		
		if(sizeofWidth/2>=sizeofHeight)
		{
				here.width = System.Convert.ToSingle((curNode.myRectangle.width*(Random.Range(7,9)*.1)));
				here.width = Mathf.Floor(here.width);
				here.height = System.Convert.ToSingle( (curNode.myRectangle.height*(Random.Range(8,9)*.103)));
				here.height = Mathf.Floor(here.height);
				here.y = curNode.myRectangle.y+((curNode.myRectangle.height-here.height)/2);
				here.x = curNode.myRectangle.x+((curNode.myRectangle.width-here.width)/2);
				here.x = Mathf.Floor(here.x);
				here.y = Mathf.Floor(here.y);
				curNode.myRoom = here;
				roomsforShow.Add(curNode.myRoom);
				leafs.Add(curNode);
				breakout = true;
		}
		
		if(breakout) return;
		
		if(sizeofWidth<sizeofHeight/2)
		{
			here.height =System.Convert.ToSingle( (curNode.myRectangle.height*(Random.Range(7,9)*.1)));
			here.height = Mathf.Floor(here.height);
				here.width =System.Convert.ToSingle( (curNode.myRectangle.width*(Random.Range(8,9)*.103)));
			here.width = Mathf.Floor(here.width);
				here.x = curNode.myRectangle.x+((curNode.myRectangle.width-here.width)/2);
				here.y = curNode.myRectangle.y+((curNode.myRectangle.height-here.height)/2);
				here.x = Mathf.Floor(here.x);
				here.y = Mathf.Floor(here.y);
				curNode.myRoom = here;
				roomsforShow.Add(curNode.myRoom);
				leafs.Add(curNode);
				breakout = true;
		}
		
			if(breakout) return;
				
				here.height = System.Convert.ToSingle( (curNode.myRectangle.height*(Random.Range(7,9)*.1)));
				here.height = Mathf.Floor(here.height);
				here.width =System.Convert.ToSingle( (curNode.myRectangle.width*(Random.Range(7,9)*.10)));
				here.width = Mathf.Floor(here.width);
				here.x = curNode.myRectangle.x+((curNode.myRectangle.width-here.width)/2);
				here.y = curNode.myRectangle.y+((curNode.myRectangle.height-here.height)/2);
				here.x = Mathf.Floor(here.x);
				here.y = Mathf.Floor(here.y);
				curNode.myRoom = here;
				roomsforShow.Add(curNode.myRoom);
				leafs.Add(curNode);
				breakout = true;
		if(breakout) return;
		
	}
	
	
	public void generateCorridor(List<Node> workLoad)
	{
		bool enders = false;
		List<Node> nextWork = new List<Node>();
		if (workLoad[0].children[0]==null)
		{
			howMany++;
		for(int i = 0;i<(workLoad.Count);i+=2)
		{
			if(workLoad[i].parent.HorzTrue)
			{
				float minx, maxx;
				if(workLoad[i].myRoom.x>=workLoad[i+1].myRoom.x)
					{
					minx =	workLoad[i].myRoom.x;
					}
					else
					{
					minx = workLoad[i+1].myRoom.x;	
					}
					
					
					if(workLoad[i].myRoom.x+workLoad[i].myRoom.width<=workLoad[i+1].myRoom.x+workLoad[i+1].myRoom.width)
					{
						maxx = workLoad[i].myRoom.x+workLoad[i].myRoom.width;
					}
					else
					{
					maxx = workLoad[i+1].myRoom.x+workLoad[i+1].myRoom.width;	
					}
				nextWork.Add(workLoad[i].parent);
				Rectangles cor = new Rectangles();
				cor.y = workLoad[i].myRoom.y+workLoad[i].myRoom.height;
				cor.x = Random.Range(minx+2,maxx-2);
				cor.x = Mathf.Floor(cor.x);
				cor.height = workLoad[i+1].myRoom.y-(workLoad[i].myRoom.y+workLoad[i].myRoom.height);
				cor.width = 3;
				hallways.Add(cor);
			}
			else
			{
					float miny,maxy;
					
					if(workLoad[i].myRoom.y>workLoad[i+1].myRoom.y)
					{
					miny =	workLoad[i].myRoom.y;
					}
					else
					{
					miny = workLoad[i+1].myRoom.y;	
					}
					
					
					if(workLoad[i].myRoom.y+workLoad[i].myRoom.height<workLoad[i+1].myRoom.y+workLoad[i+1].myRoom.height)
					{
						maxy = workLoad[i].myRoom.y+workLoad[i].myRoom.height;
					}
					else
					{
					maxy = workLoad[i+1].myRoom.y+workLoad[i+1].myRoom.height;	
					}
					
					
				nextWork.Add(workLoad[i].parent);
				Rectangles cor = new Rectangles();
				cor.x = workLoad[i].myRoom.x+workLoad[i].myRoom.width;
				cor.y = Random.Range(miny+2,maxy-2);
				cor.y = Mathf.Floor(cor.y);
				cor.width = workLoad[i+1].myRoom.x-(workLoad[i].myRoom.x+workLoad[i].myRoom.width);
				cor.height = 3;
				hallways.Add(cor);
			}
			}
			enders = true;
			generateCorridor(nextWork);
		}
		if(enders) return;
		
		List<Node> nextList = new List<Node>();
		if(workLoad.Count>1)
		{
			howMany++;
			for(int l = 0;l<workLoad.Count;l+=2)
			{
				nextList.Add(workLoad[l].parent);
			if(workLoad[l].parent.HorzTrue)
				{
					Aers = null;
					Bers = null;
					for (int r = 0;r<leafs.Count/workLoad.Count;r++)
					{
						int aPlace = (l*(leafs.Count/workLoad.Count))+r;
						int bPlace = ((l+1)*(leafs.Count/workLoad.Count))+r;
						
					
						aa = Mathf.Floor(leafs[aPlace].myRectangle.y+leafs[aPlace].myRectangle.height);
						ab = Mathf.Floor(workLoad[l+1].myRectangle.y);
						ac = Mathf.Floor(leafs[aPlace].myRectangle.x);
						ad = Mathf.Floor(workLoad[l].myRectangle.x);
						
						
						if(aa==ab&&ac==ad)
						{
						Aers = leafs[aPlace];
						}
						Mathf.Floor(ba = leafs[bPlace].myRectangle.y);
						Mathf.Floor(bb = workLoad[l+1].myRectangle.y);
						Mathf.Floor(bc = leafs[bPlace].myRectangle.x);
						Mathf.Floor(bd = workLoad[l].myRectangle.x);
						
						
						if(ba==bb&&bc==bd)
						{
							Bers = leafs[bPlace];
						}
						if (Aers!=null&&Bers!=null) break;
					}
					if(Aers == null)
					{
						Debug.Log("Aers is null Horz");
					}
					if(Bers == null)
					{
						Debug.Log("Bers is null Horz");
					}
					
					Rectangles cor = new Rectangles();
				float minx, maxx;
				if(Aers.myRoom.x>=Bers.myRoom.x)
					{
					minx =	Aers.myRoom.x;
					}
					else
					{
					minx = Bers.myRoom.x;	
					}
					
					
					if(Aers.myRoom.x+Aers.myRoom.width<=Bers.myRoom.x+Bers.myRoom.width)
					{
						maxx = Aers.myRoom.x+Aers.myRoom.width;
					}
					else
					{
					maxx = Bers.myRoom.x+Bers.myRoom.width;	
					}
				cor.y = Aers.myRoom.y+Aers.myRoom.height;
				cor.x = Random.Range(minx+2,maxx-2);
				cor.x = Mathf.Floor(cor.x);
				cor.height = Bers.myRoom.y-(Aers.myRoom.y+Aers.myRoom.height);
				cor.width = 3;
				hallways.Add(cor);
			
				}
				else
				{
				
					Aers = null;
					 Bers = null;
				
					for (int r = 0;r<leafs.Count/workLoad.Count;r++)
					{
						int aPlace = (l*(leafs.Count/workLoad.Count))+r;
						int bPlace = ((l+1)*(leafs.Count/workLoad.Count))+r;
						
			
						aa = Mathf.Floor(leafs[aPlace].myRectangle.x+leafs[aPlace].myRectangle.width);
						ab = Mathf.Floor(workLoad[l+1].myRectangle.x);
						ac = Mathf.Floor(leafs[aPlace].myRectangle.y);
						ad = Mathf.Floor(workLoad[l].myRectangle.y);
						
						if(aa==ab&&ac==ad)
						{
						Aers = leafs[aPlace];
						}
						
						ba = Mathf.Floor(leafs[bPlace].myRectangle.x);
						bb = Mathf.Floor(workLoad[l+1].myRectangle.x);
						bc = Mathf.Floor(leafs[bPlace].myRectangle.y);
						bd = Mathf.Floor(workLoad[l].myRectangle.y);
						
						if(ba==bb&&bc==bd)
						{
							Bers = leafs[bPlace];
						}
						
						if (Aers!=null&&Bers!=null) break;
					}
					if(Aers == null)
					{
						Debug.Log("Aers is null Vert");
					}
					if(Bers == null)
					{
						Debug.Log("Bers is null Vert");
					}
					Rectangles cor = new Rectangles();
					float miny,maxy;
					
					if(Aers.myRoom.y>Bers.myRoom.y)
					{
					miny =	Aers.myRoom.y;
					}
					else
					{
					miny = Bers.myRoom.y;	
					}
					
					
					if(Aers.myRoom.y+Aers.myRoom.height<Bers.myRoom.y+Bers.myRoom.height)
					{
						maxy = Aers.myRoom.y+Aers.myRoom.height;
					}
					else
					{
					maxy = Bers.myRoom.y+Bers.myRoom.height;	
					}
				cor.x = Aers.myRoom.x+Aers.myRoom.width;
				cor.y = Random.Range(miny+2,maxy-2);
				cor.y = Mathf.Floor(cor.y);
				cor.height = 3;
				cor.width = Bers.myRoom.x-(Aers.myRoom.x+Aers.myRoom.width);
				hallways.Add(cor);
			
				}	
					
					
				
				
			}
			
				
				generateCorridor(nextList);
			}
			
			
	}
		

	
	
	public void splitHorz(Node curNode)
	{
		curNode.HorzTrue = true;
		
		float sizeofWidth = curNode.myRectangle.width;
		float sizeofHeight = curNode.myRectangle.height;
		
			float wheres = Random.Range(sizeofHeight*1/3,sizeofHeight*2/3);
				wheres = Mathf.Floor(wheres);
				Point st = new Point(curNode.myRectangle.x,(curNode.myRectangle.y+wheres));
				Point ed = new Point(sizeofWidth,(curNode.myRectangle.y+wheres));
				curNode.splitLine = new Line(st,ed);	
				curNode.didSplit = true;
				//Rectangles chi1 = );
				//Rectangles chi2 = 
				curNode.children[0] = new Node();
				curNode.children[1] = new Node();
				curNode.children[0].AddRectangle(new Rectangles(curNode.myRectangle.x,curNode.myRectangle.y,sizeofWidth,wheres));
				curNode.children[1].AddRectangle(new Rectangles(curNode.myRectangle.x,(curNode.myRectangle.y+wheres),sizeofWidth,sizeofHeight-wheres));
				
				//curNode.children[0].sister=curNode.children[1];
				//curNode.children[1].sister=curNode.children[0];
		
				curNode.children[0].parent = curNode;
				curNode.children[1].parent = curNode;
				
				listOfSplits.Add(new Line(st,ed));
	}
	
	public void splitVert(Node curNode)
	{
		float sizeofWidth = curNode.myRectangle.width;
		float sizeofHeight = curNode.myRectangle.height;
		
		
		float wheres = Random.Range(sizeofWidth*1/3,sizeofWidth*2/3);
		wheres = Mathf.Floor(wheres);
				Point st = new Point(curNode.myRectangle.x+wheres,curNode.myRectangle.y);
				Point ed = new Point(curNode.myRectangle.x+wheres,sizeofHeight);
				curNode.splitLine = new Line(st,ed);	
				curNode.didSplit = true;
				Rectangles chi1 = new Rectangles(curNode.myRectangle.x,curNode.myRectangle.y,wheres,sizeofHeight);
				Rectangles chi2 = new Rectangles(curNode.myRectangle.x+wheres,curNode.myRectangle.y,sizeofWidth-wheres,sizeofHeight);
				curNode.children[0] = new Node();
				curNode.children[1] = new Node();
				curNode.children[0].AddRectangle(chi1);
				curNode.children[1].AddRectangle(chi2);
		
				//curNode.children[0].sister=curNode.children[1];
				//curNode.children[1].sister=curNode.children[0];
		
				curNode.children[0].parent = curNode;
				curNode.children[1].parent = curNode;
			
				listOfSplits.Add(new Line(st,ed));
				//Debug.Log("Yup2");
		
	}
	
	
	
	
}
